import { ConfigService } from '@nestjs/config'
import { Logger } from '@nestjs/common'
import { LoggerUtil, LogContext } from './logger.util'

/**
 * 应用配置接口
 */
export interface AppConfig {
  port: number
  environment: string
  apiPrefix: string
  corsOrigins: string[]
  rateLimitMax: number
  rateLimitWindowMs: number
}

/**
 * 数据库配置接口
 */
export interface DatabaseConfig {
  url: string
  maxConnections: number
  connectionTimeout: number
  queryTimeout: number
  logQueries: boolean
}

/**
 * JWT配置接口
 */
export interface JwtConfig {
  secret: string
  expiresIn: string
  refreshSecret: string
  refreshExpiresIn: string
  issuer: string
  audience: string
}

/**
 * 文件上传配置接口
 */
export interface UploadConfig {
  maxFileSize: number
  maxFiles: number
  allowedImageTypes: string[]
  allowedDocumentTypes: string[]
  uploadPath: string
  baseUrl: string
  imageQuality: number
  thumbnailSizes: { width: number; height: number }[]
}

/**
 * 邮件配置接口
 */
export interface EmailConfig {
  host: string
  port: number
  secure: boolean
  user: string
  password: string
  from: string
  templates: {
    welcome: string
    resetPassword: string
    emailVerification: string
  }
}

/**
 * 缓存配置接口
 */
export interface CacheConfig {
  ttl: number
  max: number
  host?: string
  port?: number
  password?: string
  db?: number
}

/**
 * 日志配置接口
 */
export interface LogConfig {
  level: string
  maxFiles: string
  maxSize: string
  datePattern: string
  format: string
  enableConsole: boolean
  enableFile: boolean
}

/**
 * 安全配置接口
 */
export interface SecurityConfig {
  bcryptRounds: number
  sessionSecret: string
  csrfSecret: string
  rateLimitMax: number
  rateLimitWindowMs: number
  maxLoginAttempts: number
  lockoutDuration: number
}

/**
 * 分页配置接口
 */
export interface PaginationConfig {
  defaultLimit: number
  maxLimit: number
  defaultPage: number
}

/**
 * 配置管理工具类
 * 统一管理应用程序的所有配置项
 */
export class ConfigUtil {
  private static configService: ConfigService
  private static cache = new Map<string, any>()
  private static logger = new Logger(ConfigUtil.name)

  /**
   * 初始化配置服务
   * @param configService NestJS配置服务实例
   */
  static init(configService: ConfigService): void {
    this.configService = configService
  }

  /**
   * 获取应用配置
   * @returns 应用配置对象
   */
  static getAppConfig(): AppConfig {
    const cacheKey = 'app_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: AppConfig = {
      port: this.getNumber('PORT', 3000),
      environment: this.getString('NODE_ENV', 'development'),
      apiPrefix: this.getString('API_PREFIX', 'api'),
      corsOrigins: this.getStringArray('CORS_ORIGINS', ['http://localhost:3000']),
      rateLimitMax: this.getNumber('RATE_LIMIT_MAX', 100),
      rateLimitWindowMs: this.getNumber('RATE_LIMIT_WINDOW_MS', 15 * 60 * 1000)
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取数据库配置
   * @returns 数据库配置对象
   */
  static getDatabaseConfig(): DatabaseConfig {
    const cacheKey = 'database_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: DatabaseConfig = {
      url: this.getString('DATABASE_URL', ''),
      maxConnections: this.getNumber('DB_MAX_CONNECTIONS', 10),
      connectionTimeout: this.getNumber('DB_CONNECTION_TIMEOUT', 30000),
      queryTimeout: this.getNumber('DB_QUERY_TIMEOUT', 10000),
      logQueries: this.getBoolean('DB_LOG_QUERIES', false)
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取JWT配置
   * @returns JWT配置对象
   */
  static getJwtConfig(): JwtConfig {
    const cacheKey = 'jwt_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: JwtConfig = {
      secret: this.getString('JWT_SECRET', 'your-secret-key'),
      expiresIn: this.getString('JWT_EXPIRES_IN', '1h'),
      refreshSecret: this.getString('JWT_REFRESH_SECRET', 'your-refresh-secret'),
      refreshExpiresIn: this.getString('JWT_REFRESH_EXPIRES_IN', '7d'),
      issuer: this.getString('JWT_ISSUER', 'nodejs-cms'),
      audience: this.getString('JWT_AUDIENCE', 'nodejs-cms-users')
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取文件上传配置
   * @returns 文件上传配置对象
   */
  static getUploadConfig(): UploadConfig {
    const cacheKey = 'upload_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: UploadConfig = {
      maxFileSize: this.getNumber('UPLOAD_MAX_FILE_SIZE', 10 * 1024 * 1024), // 10MB
      maxFiles: this.getNumber('UPLOAD_MAX_FILES', 5),
      allowedImageTypes: this.getStringArray('UPLOAD_ALLOWED_IMAGE_TYPES', [
        'image/jpeg',
        'image/png',
        'image/webp',
        'image/gif'
      ]),
      allowedDocumentTypes: this.getStringArray('UPLOAD_ALLOWED_DOCUMENT_TYPES', [
        'application/pdf',
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'text/plain'
      ]),
      uploadPath: this.getString('UPLOAD_PATH', './uploads'),
      baseUrl: this.getString('UPLOAD_BASE_URL', 'http://localhost:3000'),
      imageQuality: this.getNumber('UPLOAD_IMAGE_QUALITY', 80),
      thumbnailSizes: [
        { width: 150, height: 150 },
        { width: 300, height: 300 },
        { width: 600, height: 600 }
      ]
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取邮件配置
   * @returns 邮件配置对象
   */
  static getEmailConfig(): EmailConfig {
    const cacheKey = 'email_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: EmailConfig = {
      host: this.getString('EMAIL_HOST', 'localhost'),
      port: this.getNumber('EMAIL_PORT', 587),
      secure: this.getBoolean('EMAIL_SECURE', false),
      user: this.getString('EMAIL_USER', ''),
      password: this.getString('EMAIL_PASSWORD', ''),
      from: this.getString('EMAIL_FROM', 'noreply@example.com'),
      templates: {
        welcome: this.getString('EMAIL_TEMPLATE_WELCOME', 'welcome'),
        resetPassword: this.getString('EMAIL_TEMPLATE_RESET_PASSWORD', 'reset-password'),
        emailVerification: this.getString('EMAIL_TEMPLATE_EMAIL_VERIFICATION', 'email-verification')
      }
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取缓存配置
   * @returns 缓存配置对象
   */
  static getCacheConfig(): CacheConfig {
    const cacheKey = 'cache_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: CacheConfig = {
      ttl: this.getNumber('CACHE_TTL', 300), // 5 minutes
      max: this.getNumber('CACHE_MAX', 1000),
      host: this.getString('REDIS_HOST'),
      port: this.getNumber('REDIS_PORT'),
      password: this.getString('REDIS_PASSWORD'),
      db: this.getNumber('REDIS_DB', 0)
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取日志配置
   * @returns 日志配置对象
   */
  static getLogConfig(): LogConfig {
    const cacheKey = 'log_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: LogConfig = {
      level: this.getString('LOG_LEVEL', 'info'),
      maxFiles: this.getString('LOG_MAX_FILES', '14d'),
      maxSize: this.getString('LOG_MAX_SIZE', '20m'),
      datePattern: this.getString('LOG_DATE_PATTERN', 'YYYY-MM-DD'),
      format: this.getString('LOG_FORMAT', 'json'),
      enableConsole: this.getBoolean('LOG_ENABLE_CONSOLE', true),
      enableFile: this.getBoolean('LOG_ENABLE_FILE', true)
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取安全配置
   * @returns 安全配置对象
   */
  static getSecurityConfig(): SecurityConfig {
    const cacheKey = 'security_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: SecurityConfig = {
      bcryptRounds: this.getNumber('BCRYPT_ROUNDS', 12),
      sessionSecret: this.getString('SESSION_SECRET', 'your-session-secret'),
      csrfSecret: this.getString('CSRF_SECRET', 'your-csrf-secret'),
      rateLimitMax: this.getNumber('RATE_LIMIT_MAX', 100),
      rateLimitWindowMs: this.getNumber('RATE_LIMIT_WINDOW_MS', 15 * 60 * 1000),
      maxLoginAttempts: this.getNumber('MAX_LOGIN_ATTEMPTS', 5),
      lockoutDuration: this.getNumber('LOCKOUT_DURATION', 15 * 60 * 1000) // 15 minutes
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取分页配置
   * @returns 分页配置对象
   */
  static getPaginationConfig(): PaginationConfig {
    const cacheKey = 'pagination_config'
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)
    }

    const config: PaginationConfig = {
      defaultLimit: this.getNumber('PAGINATION_DEFAULT_LIMIT', 10),
      maxLimit: this.getNumber('PAGINATION_MAX_LIMIT', 100),
      defaultPage: this.getNumber('PAGINATION_DEFAULT_PAGE', 1)
    }

    this.cache.set(cacheKey, config)
    return config
  }

  /**
   * 获取字符串配置值
   * @param key 配置键
   * @param defaultValue 默认值
   * @returns 配置值
   */
  static getString(key: string, defaultValue?: string): string {
    if (!this.configService) {
      throw new Error('ConfigService not initialized. Call ConfigUtil.init() first.')
    }
    return this.configService.get<string>(key, defaultValue)
  }

  /**
   * 获取数字配置值
   * @param key 配置键
   * @param defaultValue 默认值
   * @returns 配置值
   */
  static getNumber(key: string, defaultValue?: number): number {
    if (!this.configService) {
      throw new Error('ConfigService not initialized. Call ConfigUtil.init() first.')
    }
    const value = this.configService.get<string>(key)
    if (value === undefined || value === null) {
      return defaultValue
    }
    const parsed = parseInt(value, 10)
    return isNaN(parsed) ? defaultValue : parsed
  }

  /**
   * 获取布尔配置值
   * @param key 配置键
   * @param defaultValue 默认值
   * @returns 配置值
   */
  static getBoolean(key: string, defaultValue?: boolean): boolean {
    if (!this.configService) {
      throw new Error('ConfigService not initialized. Call ConfigUtil.init() first.')
    }
    const value = this.configService.get<string>(key)
    if (value === undefined || value === null) {
      return defaultValue
    }
    return value.toLowerCase() === 'true' || value === '1'
  }

  /**
   * 获取字符串数组配置值
   * @param key 配置键
   * @param defaultValue 默认值
   * @returns 配置值
   */
  static getStringArray(key: string, defaultValue?: string[]): string[] {
    if (!this.configService) {
      throw new Error('ConfigService not initialized. Call ConfigUtil.init() first.')
    }
    const value = this.configService.get<string>(key)
    if (value === undefined || value === null) {
      return defaultValue || []
    }
    return value
      .split(',')
      .map(item => item.trim())
      .filter(item => item.length > 0)
  }

  /**
   * 获取JSON配置值
   * @param key 配置键
   * @param defaultValue 默认值
   * @returns 配置值
   */
  static getJson<T>(key: string, defaultValue?: T): T {
    if (!this.configService) {
      throw new Error('ConfigService not initialized. Call ConfigUtil.init() first.')
    }
    const value = this.configService.get<string>(key)
    if (value === undefined || value === null) {
      return defaultValue
    }
    try {
      return JSON.parse(value)
    } catch (error) {
      LoggerUtil.error(ConfigUtil.logger, '配置解析失败', error, { key, value })
      return defaultValue
    }
  }

  /**
   * 检查配置是否为生产环境
   * @returns 是否为生产环境
   */
  static isProduction(): boolean {
    return this.getAppConfig().environment === 'production'
  }

  /**
   * 检查配置是否为开发环境
   * @returns 是否为开发环境
   */
  static isDevelopment(): boolean {
    return this.getAppConfig().environment === 'development'
  }

  /**
   * 检查配置是否为测试环境
   * @returns 是否为测试环境
   */
  static isTest(): boolean {
    return this.getAppConfig().environment === 'test'
  }

  /**
   * 清除配置缓存
   * @param key 可选的特定键，如果不提供则清除所有缓存
   */
  static clearCache(key?: string): void {
    if (key) {
      this.cache.delete(key)
    } else {
      this.cache.clear()
    }
  }

  /**
   * 获取所有配置的摘要（用于调试）
   * @returns 配置摘要对象
   */
  static getConfigSummary(): Record<string, any> {
    return {
      app: {
        environment: this.getAppConfig().environment,
        port: this.getAppConfig().port,
        apiPrefix: this.getAppConfig().apiPrefix
      },
      database: {
        hasUrl: !!this.getDatabaseConfig().url,
        maxConnections: this.getDatabaseConfig().maxConnections
      },
      upload: {
        maxFileSize: this.getUploadConfig().maxFileSize,
        uploadPath: this.getUploadConfig().uploadPath
      },
      security: {
        bcryptRounds: this.getSecurityConfig().bcryptRounds,
        maxLoginAttempts: this.getSecurityConfig().maxLoginAttempts
      },
      cache: {
        ttl: this.getCacheConfig().ttl,
        max: this.getCacheConfig().max
      }
    }
  }

  /**
   * 验证必需的配置项
   * @param requiredKeys 必需的配置键数组
   * @throws 如果缺少必需配置则抛出错误
   */
  static validateRequiredConfig(requiredKeys: string[]): void {
    const missing: string[] = []

    for (const key of requiredKeys) {
      const value = this.getString(key)
      if (!value) {
        missing.push(key)
      }
    }

    if (missing.length > 0) {
      throw new Error(`Missing required configuration: ${missing.join(', ')}`)
    }
  }
}